package com.magold.logic;

import java.util.Iterator;
import java.util.LinkedList;

import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.AlphaModifier;
import org.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.shape.IAreaShape;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.util.modifier.IModifier;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.magold.context.IContext;
import com.magold.context.IFixedEngine;
import com.magold.logic.polygon.CircleShape;
import com.magold.logic.polygon.MetalPrimitive;
import com.magold.logic.polygon.PrimitiveLogic;
import com.magold.logic.polygon.PrimitiveShape;
import com.magold.physics.MagoldPhysicsConnector;
import com.magold.skill.cast.AttacherManager;
import com.magold.skill.cast.MagnetAttacher;

/*package*/ class EjectaCreator {
	private static float sDistance;
	private static float sPrimitiveRadius;
	
	public static void customize(float pPrimitiveRadius, float pDistance) {
		sPrimitiveRadius = pPrimitiveRadius;
		sDistance = pDistance;
	}
	
	//===============================================================
	
	private final LinkedList<PrimitiveLogic> mEjectaQueue;
	private final Ejector mEjector;
	private final float mLifeCycle;
	private final float mVolecity;
	
	public EjectaCreator(Ejector pEjector, float pLifeCycle, float pVolecity) {
		mEjectaQueue = new LinkedList<PrimitiveLogic>();
		mEjector = pEjector;
		mLifeCycle = pLifeCycle;
		mVolecity = pVolecity;
	}

	public void createEjecta(Scene pScene, final IContext pContext, final PhysicsWorld pWorld, float pScale) {
		Vector2 point = mEjector.getJetPos();
		Vector2 volecity = mEjector.getDirect().mul(mVolecity);
		
		float radius = pScale * sPrimitiveRadius;
		float x = point.x - radius;
		float y = point.y - radius;
		PrimitiveShape shape = new CircleShape(radius);
		final PrimitiveLogic primitive = new MetalPrimitive(shape, BodyType.DynamicBody);
		primitive.createSceneData(x, y, 0, pScale, pScene);
		primitive.createPhysicsData(pWorld);
		primitive.getBody().setLinearVelocity(volecity);

		final IAreaShape sprite = primitive.getSprite();
		sprite.setZIndex(-1);
		pScene.sortChildren();
		AttacherManager am = pContext.getAttacherManager();
		float[] sceneCenter = sprite.getSceneCenterCoordinates();
		final MagnetAttacher attacher = am.createAttacher(sceneCenter[0], sceneCenter[1], sDistance, primitive.findPhysicsConnector(shape));
		
		mEjectaQueue.addLast(primitive);
		
		sprite.registerUpdateHandler(new IUpdateHandler(){
			private float mEjectaUpdateCount;
			@Override
			public void onUpdate(float pSecondsElapsed) {
				if(mEjectaUpdateCount >= mLifeCycle){
					Body body = primitive.getBody();
					if(body.isAwake()) return;
					
					detachEjecta(pContext.getEngine(), pWorld, primitive, attacher);
					sprite.unregisterUpdateHandler(this);
				} else {
					mEjectaUpdateCount += pSecondsElapsed;
				}
			}
			@Override
			public void reset() {
				// DO-NOTHING.
			}
		});
		
	}
	
	private void disappearModifier(final IFixedEngine pEngine, final IAreaShape pShape) {
		IEntityModifierListener listener = new IEntityModifierListener() {
			@Override
			public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) { }
			@Override
			public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
				pEngine.unregisterChildFromScene(pShape);
			}
		};
		AlphaModifier modifier = new AlphaModifier(1.0f, 1.0f, 0.0f, listener);
		pShape.registerEntityModifier(modifier);
	}
	
	private void detachEjecta(IContext pContext,PhysicsWorld pWorld, PrimitiveLogic pLogic, MagnetAttacher pAttacher) {
		AttacherManager am = pContext.getAttacherManager();
		am.removeAttacher(pAttacher);
		
		IAreaShape shape = pLogic.getSprite();
		Body body = pLogic.getBody();
		PhysicsConnector ejectaConnector = pLogic.findPhysicsConnector(shape);
		
		pWorld.unregisterPhysicsConnector(ejectaConnector);
		pWorld.destroyBody(body);

		mEjectaQueue.remove(pLogic);
		disappearModifier(pContext.getEngine(), shape);
	}
	
	public MagoldPhysicsConnector findPhysicsConnector(IAreaShape pShape) {
		Iterator<PrimitiveLogic> i = mEjectaQueue.iterator();
		while(i.hasNext()) {
			PrimitiveLogic logic = i.next();
			if(logic.getSprite() == pShape) return logic.findPhysicsConnector(pShape);
		}
		
		return null;
	}
}
